/*
Copyright (C) 1996-1997 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
// mathlib.h


#pragma once

float *float2 (float a, float b);
float *float3 (float a, float b, float c);
float *float4 (float a, float b, float c, float d);

// made this an inline instead of a define so it won't re-evaluate the value of 'x' for each usage
__inline int Q_rint (float x)
{
	return ((x > 0) ? (int) (x + 0.5) : (int) (x - 0.5));
}

#define CLAMP(min, x, max) ((x) < (min) ? (min) : (x) > (max) ? (max) : (x))

#define max2(a, b) (((a) > (b)) ? (a) : (b))
#define min2(a, b) (((a) < (b)) ? (a) : (b))
#define max3(a, b, c) (max2 (max2 (a, b), c))
#define min3(a, b, c) (min2 (min2 (a, b), c))

// these are split off so that they can be consistently determined during both the change-check and the send
// this can be useful if we ever add a protocol that does more accurate origin and angles stuff
__inline int QuantizedOrigin (float o) {return Q_rint (o * 8);}
__inline int QuantizedAngles (float a) {return Q_rint ((a * 256.0f) / 360.0f) & 255;}
__inline int QuantizedAngles16 (float a) {return Q_rint ((a * 65536.0f) / 360.0f) & 65535;}

typedef float vec2_t[2];
typedef float vec3_t[3];
typedef float vec4_t[4];

#ifndef M_PI
#define M_PI		3.14159265358979323846	// matches value in gcc v2 math.h
#endif

extern vec3_t vec3_origin;
extern	int nanmask;

#define	IS_NAN(x) (((*(int *) &x) & nanmask) == nanmask)

__inline void VectorSubtract (float *a, float *b, float *c) {c[0] = a[0] - b[0]; c[1] = a[1] - b[1]; c[2] = a[2] - b[2];}
__inline void VectorAdd (float *a, float *b, float *c) {c[0] = a[0] + b[0]; c[1] = a[1] + b[1]; c[2] = a[2] + b[2];}
__inline void VectorCopy (float *a, float *b) {b[0] = a[0]; b[1] = a[1]; b[2] = a[2];}

void VectorMA (float *veca, float scale, float *vecb, float *vecc);

void CrossProduct (float *v1, float *v2, float *cross);
float VectorNormalize (float *v);		// returns vector length
void VectorInverse (float *v);
void VectorScale (float *in, float scale, float *out);

void AngleVectors (float *angles, float *forward, float *right, float *up);
int BoxOnPlaneSide (float *emins, float *emaxs, struct mplane_t *plane);
float anglemod (float a);


#define DEG2RAD(a) (((a) * M_PI) / 180.0)
#define RAD2DEG(a) (((a) * 180.0) / M_PI)


__inline float *Vector2Copy (float *dst, const float *src)
{
	dst[0] = src[0];
	dst[1] = src[1];

	return dst;
}


__inline float *Vector3Copy (float *dst, const float *src)
{
	dst[0] = src[0];
	dst[1] = src[1];
	dst[2] = src[2];

	return dst;
}


__inline void VolatileVector3Copy (volatile float *dst, const float *src)
{
	dst[0] = src[0];
	dst[1] = src[1];
	dst[2] = src[2];
}


__inline float *Vector4Copy (float *dst, const float *src)
{
	dst[0] = src[0];
	dst[1] = src[1];
	dst[2] = src[2];
	dst[3] = src[3];

	return dst;
}


__inline void Vector2Add (float *dst, const float *vec1, const float *vec2)
{
	dst[0] = vec1[0] + vec2[0];
	dst[1] = vec1[1] + vec2[1];
}


__inline void Vector3Add (float *dst, const float *vec1, const float *vec2)
{
	dst[0] = vec1[0] + vec2[0];
	dst[1] = vec1[1] + vec2[1];
	dst[2] = vec1[2] + vec2[2];
}


__inline float *Vector2Set (float *vec, float a, float b)
{
	vec[0] = a;
	vec[1] = b;

	return vec;
}


__inline float *Vector3Set (float *vec, float a, float b, float c)
{
	vec[0] = a;
	vec[1] = b;
	vec[2] = c;

	return vec;
}


__inline float *Vector4Set (float *vec, float a, float b, float c, float d)
{
	vec[0] = a;
	vec[1] = b;
	vec[2] = c;
	vec[3] = d;

	return vec;
}


__inline float Vector2Dot (const float *x, const float *y)
{
	return (x[0] * y[0]) + (x[1] * y[1]);
}


__inline float Vector3Dot (const float *x, const float *y)
{
	return (x[0] * y[0]) + (x[1] * y[1]) + (x[2] * y[2]);
}


__inline float Vector3DotH (const float *x, const float *y, float h)
{
	return (x[0] * y[0]) + (x[1] * y[1]) + (x[2] * y[2]) + h;
}


__inline float Vector4Dot (const float *x, const float *y)
{
	return (x[0] * y[0]) + (x[1] * y[1]) + (x[2] * y[2]) + (x[3] * y[3]);
}


__inline int Vector3Compare (const float *x, const float *y)
{
	if (x[0] != y[0]) return 0;
	if (x[1] != y[1]) return 0;
	if (x[2] != y[2]) return 0;

	return 1;
}


__inline void Vector3Mad (float *dst, const float *vecb, float scale, const float *veca)
{
	// order changed to match GPU MAD instruction
	dst[0] = vecb[0] * scale + veca[0];
	dst[1] = vecb[1] * scale + veca[1];
	dst[2] = vecb[2] * scale + veca[2];
}


__inline void Vector2Lerp (float *dst, const float *l1, const float *l2, float b)
{
	dst[0] = l1[0] + (l2[0] - l1[0]) * b;
	dst[1] = l1[1] + (l2[1] - l1[1]) * b;
}


__inline void Vector3Lerp (float *dst, const float *l1, const float *l2, float b)
{
	dst[0] = l1[0] + (l2[0] - l1[0]) * b;
	dst[1] = l1[1] + (l2[1] - l1[1]) * b;
	dst[2] = l1[2] + (l2[2] - l1[2]) * b;
}


__inline void Vector4Lerp (float *dst, const float *l1, const float *l2, float b)
{
	dst[0] = l1[0] + (l2[0] - l1[0]) * b;
	dst[1] = l1[1] + (l2[1] - l1[1]) * b;
	dst[2] = l1[2] + (l2[2] - l1[2]) * b;
	dst[3] = l1[3] + (l2[3] - l1[3]) * b;
}


__inline float Vector3Normalize (float *v)
{
	float length = Vector3Dot (v, v);

	if ((length = sqrtf (length)) > 0)
	{
		float ilength = 1 / length;

		v[0] *= ilength;
		v[1] *= ilength;
		v[2] *= ilength;
	}

	return length;
}


__inline void Vector3Scale (float *out, float scale, const float *in)
{
	out[0] = in[0] * scale;
	out[1] = in[1] * scale;
	out[2] = in[2] * scale;
}


__inline void Vector4Scale (float *dst, const float *vec, float scale)
{
	dst[0] = vec[0] * scale;
	dst[1] = vec[1] * scale;
	dst[2] = vec[2] * scale;
	dst[3] = vec[3] * scale;
}


__inline void Vector2Subtract (float *dst, const float *vec1, const float *vec2)
{
	dst[0] = vec1[0] - vec2[0];
	dst[1] = vec1[1] - vec2[1];
}


__inline void Vector3Subtract (float *dst, const float *vec1, const float *vec2)
{
	dst[0] = vec1[0] - vec2[0];
	dst[1] = vec1[1] - vec2[1];
	dst[2] = vec1[2] - vec2[2];
}


__inline void Vector3Cross (float *cross, const float *v1, const float *v2)
{
	cross[0] = v1[1] * v2[2] - v1[2] * v2[1];
	cross[1] = v1[2] * v2[0] - v1[0] * v2[2];
	cross[2] = v1[0] * v2[1] - v1[1] * v2[0];
}


__inline float clamp (float val, float low, float high)
{
	return (val < low) ? low : ((val > high) ? high : val);
}


__inline float mapValue (float inVal, float inFrom, float inTo, float outFrom, float outTo)
{
	float inScale = (inFrom != inTo) ? ((inVal - inFrom) / (inTo - inFrom)) : 0.0f;
	float outVal = outFrom + (inScale * (outTo - outFrom));

	outVal = (outFrom < outTo) ? clamp (outVal, outFrom, outTo) : clamp (outVal, outTo, outFrom);

	return outVal;
}


__inline void CalculateNormalVector (float *normal, const float *a, const float *b, const float *c)
{
	float ba[3] = {b[0] - a[0], b[1] - a[1], b[2] - a[2]};
	float ca[3] = {c[0] - a[0], c[1] - a[1], c[2] - a[2]};

	Vector3Cross (normal, ba, ca);
	Vector3Normalize (normal);
}


__inline float Vector3Length (float *v)
{
	float t = 0;

	t += v[0] * v[0];
	t += v[1] * v[1];
	t += v[2] * v[2];

	// don't blow up...
	if (t > 0)
		return sqrtf (t);
	else return 0;
}


__inline float Vector3Length (float *p1, float *p2)
{
	float t = 0;

	t += (p2[0] - p1[0]) * (p2[0] - p1[0]);
	t += (p2[1] - p1[1]) * (p2[1] - p1[1]);
	t += (p2[2] - p1[2]) * (p2[2] - p1[2]);

	// don't blow up...
	if (t > 0)
		return sqrtf (t);
	else return 0;
}

